package com.spring.AOP;

import com.spring.AOP.AopAnnotation.After;
import com.spring.AOP.AopAnnotation.Around;
import com.spring.AOP.AopAnnotation.Before;
import com.spring.AOP.AopInterface.AdviceExecutor;
import com.spring.AOP.AopInterface.JoinPoint;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class DefaultExecutor implements AdviceExecutor {
    private final PointCutMatcher pointCutMatcher; // 切点匹配器
    private final Map<Object, Map<Class<?>, List<Method>>> aspectAdviceMap;// 切面方法


    public DefaultExecutor(PointCutMatcher pointCutMatcher, Map<Object, Map<Class<?>, List<Method>>> aspectAdviceMap) {
        this.pointCutMatcher = pointCutMatcher;
        this.aspectAdviceMap = aspectAdviceMap;
    }
    @Override
    public   Object execute(JoinPoint joinPoint) throws InvocationTargetException, IllegalAccessException {
        Method targetMethod = joinPoint.getMethod();
        // 执行前置通知
        executeAdviceType(Before.class, targetMethod, joinPoint);
        Object result = null;
        boolean hasAroundAdvice = false;
            // 执行环绕通知
            hasAroundAdvice = executeAdviceType(Around.class, targetMethod, joinPoint);
            // 无环绕通知时执行目标方法
            if (!hasAroundAdvice) {
                result = targetMethod.invoke(joinPoint.getTarget(), joinPoint.getArgs());
            }
            // 执行后置通知
            executeAdviceType(After.class, targetMethod, joinPoint);
        return result;
    }

    private boolean executeAdviceType(Class<?> adviceType, Method targetMethod, JoinPoint joinPoint)
            throws InvocationTargetException, IllegalAccessException {
        boolean hasAroundAdvice = false;
        // 遍历所有切面
        for (Map.Entry<Object, Map<Class<?>, List<Method>>> aspectEntry : aspectAdviceMap.entrySet()) {
            Object aspectInstance = aspectEntry.getKey();
            List<Method> advices = aspectEntry.getValue().getOrDefault(adviceType, List.of());
            // 执行该切面下的所有对应类型通知
            for (Method adviceMethod : advices) {
                // 委托给解析器处理切点表达式和匹配逻辑
                if (pointCutMatcher.matches(adviceMethod, targetMethod)) {
                    // 执行通知（传递连接点）
                    adviceMethod.invoke(aspectInstance, joinPoint);
                    // 标记环绕通知
                    if (adviceType == Around.class) {
                        hasAroundAdvice = true;
                    }
                }
            }
        }
        return hasAroundAdvice;
    }
}
